package com.wxzhou.wangzhuan.util;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

public class ApiSecurityUtils {
    
    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
    
    /**
     * 生成随机盐值
     */
    public static String generateSalt(int length) {
        byte[] salt = new byte[length];
        SECURE_RANDOM.nextBytes(salt);
        return Base64.getEncoder().encodeToString(salt);
    }
    
    /**
     * 生成动态密钥
     */
    public static String generateDynamicKey(String baseSecret, String salt, String deviceFingerprint, long timestamp) {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(baseSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);
            
            String message = salt + "|" + deviceFingerprint + "|" + timestamp;
            byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
            
            // 再次哈希
            mac.reset();
            mac.init(secretKeySpec);
            String secondMessage = Base64.getEncoder().encodeToString(hash) + "|" + salt;
            byte[] finalHash = mac.doFinal(secondMessage.getBytes(StandardCharsets.UTF_8));
            
            return Base64.getEncoder().encodeToString(finalHash);
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate dynamic key", e);
        }
    }
    
    /**
     * 生成请求签名
     */
    public static String generateRequestSignature(String dynamicKey, String endpoint, String encryptedBody, long timestamp) {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(dynamicKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);
            
            String message = endpoint + "|" + encryptedBody + "|" + timestamp;
            byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
            
            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate request signature", e);
        }
    }

    /**
     * 生成请求签名
     */
    public static String generateRequestSignature(String dynamicKey, String encryptedBody, long timestamp) {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(dynamicKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);

            String message = encryptedBody + "|" + timestamp;
            byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));

            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate request signature", e);
        }
    }

    /**
     * 生成响应签名
     */
    public static String generateResponseSignature(String dynamicKey, String encryptedResponse, long timestamp) {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(dynamicKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);
            
            String message = encryptedResponse + "|" + timestamp;
            byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
            
            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate response signature", e);
        }
    }
    
    /**
     * AES加密
     */
    public static String encrypt(String data, String key) {
        try {
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
            // 确保密钥长度为32字节（256位）
            if (keyBytes.length != 32) {
                keyBytes = MessageDigest.getInstance("SHA-256").digest(keyBytes);
            }
            
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            
            byte[] iv = new byte[12];
            SECURE_RANDOM.nextBytes(iv);
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
            
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
            byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
            
            // 组合IV和加密数据
            byte[] combined = new byte[iv.length + encrypted.length];
            System.arraycopy(iv, 0, combined, 0, iv.length);
            System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
            
            return Base64.getEncoder().encodeToString(combined);
        } catch (Exception e) {
            throw new RuntimeException("Failed to encrypt data", e);
        }
    }
    
    /**
     * AES解密
     */
    public static String decrypt(String encryptedData, String key) {
        try {
            byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
            if (keyBytes.length != 32) {
                keyBytes = MessageDigest.getInstance("SHA-256").digest(keyBytes);
            }
            
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            
            byte[] combined = Base64.getDecoder().decode(encryptedData);
            byte[] iv = new byte[12];
            byte[] encrypted = new byte[combined.length - 12];
            
            System.arraycopy(combined, 0, iv, 0, 12);
            System.arraycopy(combined, 12, encrypted, 0, encrypted.length);
            
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
            
            byte[] decrypted = cipher.doFinal(encrypted);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("Failed to decrypt data", e);
        }
    }
    
    /**
     * 计算MD5哈希
     */
    public static String md5Hash(String data) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hash = md.digest(data.getBytes(StandardCharsets.UTF_8));
            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            throw new RuntimeException("Failed to calculate MD5 hash", e);
        }
    }
} 